package messagepasser;

/**
 * 
 * @author Rishit Shroff(rshroff)
 * @author Huimin Yang(huiminy)
 * @description Contains the description of the Logger class 
 */

import java.io.*;
import java.net.Socket;
import java.util.Timer;

/**
 * 
 * Handle a received message, put it into the inputBuffer
 * 
 * @see ListenSocket
 *
 */
class ReceiveSocket extends Thread  {

	Message message;					// received Message
	MessagePasser msgPasser;			// reference to MessagePasser Object
	ObjectInputStream inObjectStream;	// Input Object Stream
	Socket connection;					// Connection Socket
    
	/**
	 * Parameterized Constructor
	 * @param socket
	 * @param m			reference to the message Passer object
	 */
	ReceiveSocket ( Socket socket, MessagePasser m)  {
		super ();
        connection =  socket;
        msgPasser = m;
    }

	/**
	 *  Run method
	 */
	
	public void run  ()  {

        try  {
        		inObjectStream = new ObjectInputStream (connection.getInputStream ());
        		//debug
                // loop to read the incoming messages
                while ( true )  {
                
                	message = (Message)inObjectStream.readObject();
                	if (message.getPayload() == null) {
            			System.out.println("socket receive null payload");
            		} else {
            		//	System.out.println("socket receive payload == " + message.getPayload());
            		}
                	
                	synchronized (msgPasser) {
                		//check for drop and delay types
                		//Lab1
                		if(msgPasser.getMyName().equals("logger") == false) {
                			if (message.isMulticastMsg()) {
                    				TimeStampedMessage msg = (TimeStampedMessage)message;
                    				// debug
                    				System.out.println("Socket recv multi, physical sender is " + msg.getPhySender());
                    				                    				
                    				if(msg.getMsgType().equals("ack")) {
                    					//debug
                    					System.out.println("Got ack from " + msg.getHeader().getSrc());
                    					msgPasser.updateAckOfMsg(msg);
                    				}
                    				if(msg.getMsgType().equals("ok")) {
                    					//debug
                    					System.out.println("Got ok from " + msg.getHeader().getSrc());
                    					msgPasser.moveToInputBuffer(msg);
                    				}
                    				else {
                    				
	                    				// network drop delay duplicate simulation
	                    				String process = msgPasser.findOp(message);
	                    				if (process.equals("drop")) {
	                    					return;
	                    					// message is dropped and never delivered
	                    				} else if (process.equals("delay")) {
	                    					msgPasser.addToNetworkBuffer(message);
	                    				} else if (process.equals("duplicate")) {
	                    					// add twice
	                    					msgPasser.addToReadyBuffer(message);
	                    					msgPasser.networkToReady(); //probably delayed message
	                    					msgPasser.addToReadyBuffer(message);
	                    				} else {
	                    					msgPasser.addToReadyBuffer(message);
	                    					msgPasser.networkToReady();
	                    				}
                    				
	                    				if (msgPasser.readyToReceive()) {
	                    					for ( Message readyMessage : msgPasser.getReadyBuffer()) {
	                    						msgPasser.acceptRealMessage((TimeStampedMessage)readyMessage);
	                    					}
	                    					msgPasser.emptyReadyBuffer();
	                    				
	                    				}
                    				}
                    		} 
                    		else {
                    				msgPasser.recvStamp((TimeStampedMessage)message);
                    				msgPasser.getInputBuffer().add(message);
                    	    }
                    	}
                	}
                	message = null;
                }  
        }
        catch ( Exception except ) {
                try  {
                    connection.close ();
                    return;
                }
                catch ( Exception e )  {
                    e.printStackTrace ();
                    return;
                }
         }
    }
}
